from __future__ import absolute_import

import wx
import os
import shutil
import threading
import time
import re
import platform

from Cura.gui import preferencesDialog
from Cura.gui.util import taskbar
from Cura.util import profile
from Cura.util import sliceRun
from Cura.util import explorer
from Cura.util import gcodeInterpreter

class sliceProgressPanel(wx.Panel):
	def __init__(self, mainWindow, parent, filelist):
		wx.Panel.__init__(self, parent, -1)
		self.mainWindow = mainWindow
		self.filelist = filelist
		self.abort = False
		
		box = wx.StaticBox(self, -1, filelist[0])
		self.sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)

		mainSizer = wx.BoxSizer(wx.VERTICAL) 
		mainSizer.Add(self.sizer, 0, flag=wx.EXPAND)

		self.statusText = wx.StaticText(self, -1, "Starting...")
		self.progressGauge = wx.Gauge(self, -1)
		self.progressGauge.SetRange(10000 * len(filelist))
		self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT)
		self.sizer.Add(self.statusText, 2, flag=wx.ALIGN_CENTER )
		self.sizer.Add(self.progressGauge, 2)
		self.sizer.Add(self.abortButton, 0)

		self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)

		self.SetSizer(mainSizer)
		self.prevStep = 'start'
		self.totalDoneFactor = 0.0
		self.startTime = time.time()
		if profile.getPreference('save_profile') == 'True':
			profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini")
		center = profile.getMachineCenterCoords() + profile.getObjectMatrix()
		cmdList = [sliceRun.getSliceCommand(sliceRun.getExportFilename(self.filelist[0]), ['|'.join(self.filelist)], [center])]
		self.thread = WorkerThread(self, filelist, cmdList)
	
	def OnAbort(self, e):
		if self.abort:
			self.mainWindow.removeSliceProgress(self)
		else:
			self.abort = True
	
	def OnShowGCode(self, e):
		self.mainWindow.preview3d.loadModelFiles(self.filelist)
		self.mainWindow.preview3d.setViewMode("GCode")
	
	def OnShowLog(self, e):
		LogWindow('\n'.join(self.progressLog))
	
	def OnOpenFileLocation(self, e):
		explorer.openExplorer(sliceRun.getExportFilename(self.filelist[0]))
	
	def OnCopyToSD(self, e):
		if profile.getPreference('sdpath') == '':
			wx.MessageBox("You need to configure your SD card drive first before you can copy files to it.\nOpening the preferences now.", 'No SD card drive.', wx.OK | wx.ICON_INFORMATION)
			prefDialog = preferencesDialog.preferencesDialog(self.GetParent())
			prefDialog.Centre()
			prefDialog.Show(True)
			if profile.getPreference('sdpath') == '':
				print "No path set"
				return
		exportFilename = sliceRun.getExportFilename(self.filelist[0])
		filename = os.path.basename(exportFilename)
		if profile.getPreference('sdshortnames') == 'True':
			filename = sliceRun.getShortFilename(filename)
		try:
			shutil.copy(exportFilename, os.path.join(profile.getPreference('sdpath'), filename))
		except:
			self.GetParent().preview3d.ShowWarningPopup("Failed to copy file to SD card.")
			return
		self.GetParent().preview3d.ShowWarningPopup("Copy finished, safely remove SD card?", self.OnSafeRemove)
	
	def OnSafeRemove(self):
		if platform.system() == "Windows":
			cmd = '"%s" %s>NUL' % (os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'EjectMedia.exe')), profile.getPreference('sdpath'))
		elif platform.system() == "Darwin":
			cmd = "diskutil eject '%s' > /dev/null 2>&1" % (profile.getPreference('sdpath'))
		else:
			cmd = "umount '%s' > /dev/null 2>&1" % (profile.getPreference('sdpath'))
		if os.system(cmd):
			self.GetParent().preview3d.ShowWarningPopup("Safe remove failed.")
		else:
			self.GetParent().preview3d.ShowWarningPopup("You can now eject the card.")

	def OnSliceDone(self, result):
		self.progressGauge.Destroy()
		self.abortButton.Destroy()
		self.progressLog = result.progressLog
		self.logButton = wx.Button(self, -1, "Show Log")
		self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT)
		self.Bind(wx.EVT_BUTTON, self.OnShowLog, self.logButton)
		self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)
		self.sizer.Add(self.logButton, 0)
		if result.returnCode == 0:
			status = "Ready: Filament: %.2fm %.2fg" % (result.gcode.extrusionAmount / 1000, result.gcode.calculateWeight() * 1000)
			status += " Print time: %02d:%02d" % (int(result.gcode.totalMoveTimeMinute / 60), int(result.gcode.totalMoveTimeMinute % 60))
			cost = result.gcode.calculateCost()
			if cost is not None:
				status += " Cost: %s" % (cost)
			self.statusText.SetLabel(status)
			if explorer.hasExplorer():
				self.openFileLocationButton = wx.Button(self, -1, "Open file location")
				self.Bind(wx.EVT_BUTTON, self.OnOpenFileLocation, self.openFileLocationButton)
				self.sizer.Add(self.openFileLocationButton, 0)
			if len(profile.getSDcardDrives()) > 0:
				self.copyToSDButton = wx.Button(self, -1, "Copy to SDCard")
				self.Bind(wx.EVT_BUTTON, self.OnCopyToSD, self.copyToSDButton)
				self.sizer.Add(self.copyToSDButton, 0)
			self.showButton = wx.Button(self, -1, "Show result")
			self.Bind(wx.EVT_BUTTON, self.OnShowGCode, self.showButton)
			self.sizer.Add(self.showButton, 0)
		else:
			self.statusText.SetLabel("Something went wrong during slicing!")
		self.sizer.Add(self.abortButton, 0)
		self.sizer.Layout()
		self.Layout()
		self.abort = True
		if self.mainWindow.preview3d.reloadModelFiles(self.filelist):
			self.mainWindow.preview3d.setViewMode("GCode")
		self.thread = None
		del result.gcode
		taskbar.setBusy(self.GetParent(), False)
	
	def SetProgress(self, stepName, layer, maxLayer):
		if self.prevStep != stepName:
			self.totalDoneFactor += sliceRun.sliceStepTimeFactor[self.prevStep]
			newTime = time.time()
			#print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName
			self.startTime = newTime
			self.prevStep = stepName
		
		progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000
		self.progressGauge.SetValue(int(progresValue))
		taskbar.setProgress(self.GetParent(), int(progresValue), self.progressGauge.GetRange())
		self.statusText.SetLabel("Preparing: processing %s [%d/%d]" % (stepName, layer, maxLayer))

class WorkerThread(threading.Thread):
	def __init__(self, notifyWindow, filelist, cmdList):
		threading.Thread.__init__(self)
		self.filelist = filelist
		self.notifyWindow = notifyWindow
		self.cmdList = cmdList
		self.fileIdx = 0
		self.start()

	def run(self):
		p = sliceRun.startSliceCommandProcess(self.cmdList[self.fileIdx])
		line = p.stdout.readline()
		self.progressLog = []
		maxValue = 1
		starttime = time.time()
		while len(line) > 0:
			line = line.rstrip()
			if line[0:9] == "Progress[" and line[-1:] == "]":
				progress = line[9:-1].split(":")
				if len(progress) > 2:
					maxValue = int(progress[2])
				wx.CallAfter(self.notifyWindow.SetProgress, progress[0], int(progress[1]), maxValue)
			else:
				self.progressLog.append("%0.2f: %s" % (time.time() - starttime, line))
				wx.CallAfter(self.notifyWindow.statusText.SetLabel, line)
			if self.notifyWindow.abort:
				p.terminate()
				wx.CallAfter(self.notifyWindow.mainWindow.removeSliceProgress, self.notifyWindow)
				return
			line = p.stdout.readline()
		line = p.stderr.readline()
		while len(line) > 0:
			line = line.rstrip()
			self.progressLog.append(line)
			line = p.stderr.readline()
		self.returnCode = p.wait()
		self.fileIdx += 1
		if self.fileIdx == len(self.cmdList):
			gcodeFilename = sliceRun.getExportFilename(self.filelist[0])
			gcodefile = open(gcodeFilename, "a")
			for logLine in self.progressLog:
				if logLine.startswith('Model error('):
					gcodefile.write(';%s\n' % (logLine))
			gcodefile.close()
			self.gcode = gcodeInterpreter.gcode()
			self.gcode.load(gcodeFilename)
			profile.replaceGCodeTags(gcodeFilename, self.gcode)
			wx.CallAfter(self.notifyWindow.OnSliceDone, self)
		else:
			self.run()

class LogWindow(wx.Frame):
	def __init__(self, logText):
		super(LogWindow, self).__init__(None, title="Slice log")
		self.textBox = wx.TextCtrl(self, -1, logText, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_READONLY)
		self.SetSize((400,300))
		self.Centre()
		self.Show(True)

